package com.googlecode.bip.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Properties;
import java.util.TimeZone;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import com.googlecode.bip.dao.DAOFactory;
import com.googlecode.bip.dao.QuestionDAO;
import com.googlecode.bip.dao.ReferentDAO;
import com.googlecode.bip.dao.TopicDAO;
import com.googlecode.bip.dao.UserDAO;
import com.googlecode.bip.entity.IQuestion;
import com.googlecode.bip.entity.IReferent;
import com.googlecode.bip.entity.ITopic;
import com.googlecode.bip.entity.IUser;
import cx.ath.choisnet.sql.DataSourceFactory;

public class BipDAOTestHelper
{
    private final static transient Logger logger = Logger.getLogger( BipDAOTestHelper.class );

    private static boolean initContextDone = false;
    private static boolean initConfigDone = false;

    private static String dbdriverClassName;
    private static String dburl;
    private static String dbusername;
    private static String dbpassword;

    private static final PrintWriter dblogger = new PrintWriter( System.err );

    private static String getPropertiesFileName()
    {
        // FIXME: find a way to get right filter according to maven configuration (?)
        String filterName =System.getProperty( "test.filter" );

        if( filterName == null ) {
            filterName  =  "filter-test.properties"; // improve this
            }

        return filterName;
    }

    private static void initConfigDone()
    {
        Properties  prop        = new Properties();
        String      filterName  =  getPropertiesFileName();
        File        filterFile  = null;

        try {
            File buildRootDirFile = new File( ".." ).getCanonicalFile();

            logger.debug( "buildRootDirFile=" + buildRootDirFile );
            logger.debug( "buildRootDirFile.isDirectory()=" + buildRootDirFile.isDirectory() );

            File filtersDirFile = new File( buildRootDirFile, "bip-web/src/main/filters" );

            logger.debug( "filtersDirFile=" + filtersDirFile );
            logger.debug( "filtersDirFile.isDirectory()=" + filtersDirFile.isDirectory() );

            filterFile = new File( filtersDirFile, filterName );

            logger.debug( "filterFile=" + filterFile );
            logger.debug( "filterFile.isFile()=" + filterFile.isFile() );
            }
        catch( IOException e ) {
            logger.warn( "Can not find config file (1st attempt)", e );
            }

        if( filterFile != null ) {
            if( ! filterFile.isFile() ) {
                logger.warn( "Can not find config file: " + filterFile );
                filterFile = null;
                }
            }

        if( filterFile == null ) {
            // Try direct name
            filterFile = new File( filterName );
            }

        try {
            FileInputStream propIS = new FileInputStream( filterFile );
            prop.load( propIS );
            propIS.close();

            dbdriverClassName = prop.getProperty( "jdbc.driverClassName" );
            dburl = prop.getProperty( "jdbc.url" );
            dbusername = prop.getProperty( "jdbc.username" );
            dbpassword = prop.getProperty( "jdbc.password" );

            if( "cloudbees".equals( dbdriverClassName ) ) {
                // cloudbees specific
                dbdriverClassName = prop.getProperty( "cloudbees.jdbc.driverClassName" );
                dburl = prop.getProperty( "cloudbees.jdbc.url" );
                }
            }
        catch( IOException e ) {
            logger.warn( "*** error:" + e.getMessage() );
            logger.warn( "Can not find config file (2nd attempt) - use default" );

            // Default value if can not find configuration file
            dbdriverClassName   = "com.mysql.jdbc.Driver";
            dburl               = "jdbc:mysql://localhost:3306/BiPol?autoReconnect=true";
            dbusername          = "bipol";
            dbpassword          = "bipolpass";
            }

        logger.info( "init dbdriverClassName: " + dbdriverClassName );
        logger.info( "init dburl: " + dburl );
        logger.info( "init dbusername: " + dbusername );
        logger.info( "init dbpassword (not null ?): " + (dbpassword!=null) );

        initConfigDone = true;
    }

    public synchronized static void setUpClass() throws Exception
    {
        if( initContextDone ) {
            return;
            }

        if( ! initConfigDone ) {
            initConfigDone();
            }

//        final Properties sysProp = System.getProperties();
//
//        for( Entry<Object,Object> entry : sysProp.entrySet() ) {
//            System.out.println( "n:" + entry.getKey() + "=" + entry.getValue() );
//            }

        // setup the jndi context and the datasource
        try {
            // Create initial context
            System.setProperty(
                Context.INITIAL_CONTEXT_FACTORY,
                "org.apache.naming.java.javaURLContextFactory"
                );
            System.setProperty(
                Context.URL_PKG_PREFIXES,
                "org.apache.naming"
                );

            InitialContext ic = new InitialContext();

            ic.createSubcontext("java:");
            ic.createSubcontext("java:comp");
            ic.createSubcontext("java:comp/env");
            ic.createSubcontext("java:comp/env/jdbc");

            // Construct DataSource
            //OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
            DataSource ds = DataSourceFactory.buildDataSource(
                    dbdriverClassName,
                    dburl,
                    dbusername,
                    dbpassword,
                    dblogger
                    );

            ic.bind("java:comp/env/jdbc/bipol", ds);
            }
        catch( NamingException e ) {
            logger.fatal( e );
            throw e;
            }

        initContextDone = true;
        Logger.getLogger( BipDAOTestHelper.class ).info( "setUpClass done" );
    }

    public static ITopic createTopic()
    {
        return createTopic( "fr" );
    }

    public static ITopic createTopic( String idlocal )
     {
        TopicDAO        dao                 = DAOFactory.getDAOFactory().getTopicDAO();
        final int       parentIdTopic       = 0;
        final String    topicName           = "^TEST^ Topic - name " + idlocal;
        final String    topicDescription    = "^TEST^ Topic " + idlocal;

        try {
            return dao.insertTopic( parentIdTopic, idlocal, topicName, topicDescription );
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }
    }

    public static void deleteTopic( ITopic topic )
    {
        TopicDAO dao = DAOFactory.getDAOFactory().getTopicDAO();

        try {
            dao.deleteTopicLocals( topic.getIdTopic() );
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }

        try {
            dao.deleteTopic( topic.getIdTopic() );
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }
    }

    public static List<ITopic> getAllTopics()
    {
        final List<ITopic>  topics  = new ArrayList<ITopic>();

        try {
            final TopicDAO          dao          = DAOFactory.getDAOFactory().getTopicDAO();
            final Deque<Integer>    topicIdQueue = new ArrayDeque<Integer>();

            // Root list
            List<ITopic> list = dao.getRootTopics();

            for( ITopic topic : list ) {
                topics.add( topic );
                // Store 'parentidtopic' in queue
                topicIdQueue.addFirst( topic.getIdTopic() );
                }

            // All others sub topics
            while( topicIdQueue.size()>0 ) {
                list = dao.getSubTopics( topicIdQueue.poll() );

                for( ITopic topic : list ) {
                    topics.add( topic );
                    // Store 'parentidtopic' in queue
                    topicIdQueue.addFirst( topic.getIdTopic() );
                    }
                }
            }
        catch( Exception e ) {
            logger.fatal( e );
            }

        return topics;
    }

    public static IQuestion createQuestion( ITopic topic )
    {
        return createQuestion( topic, "fr" );
    }

    public static IQuestion createQuestion( final ITopic topic, final String idlocal )
    {
        QuestionDAO dao = DAOFactory.getDAOFactory().getQuestionDAO();

        try {
            final int     minvalue        = -3;
            final int     maxvalue        = 3;
            final int     defaultvalue    = 0;
            final String  name            = "^TEST^ Question - name " + idlocal ;
            final String  description     = "^TEST^ Question - description " + idlocal;

            final IQuestion q = dao.insertQuestion( topic.getIdTopic(), minvalue , maxvalue, defaultvalue, idlocal, name, description );

            if( q != null ) {
                return q;
                }
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }

        return null;
    }

    public static void deleteQuestion( IQuestion q )
    {
        QuestionDAO dao = DAOFactory.getDAOFactory().getQuestionDAO();

        // Get all translations
        try {
            List<IQuestion> questions = dao.findQuestions( q.getIdQuestion() );

            // Delete all translations
            for( IQuestion ql : questions ) {
                dao.deleteQuestionLocal( ql.getIdQuestion(), ql.getIdLocal() );
                }
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }

        try {
            dao.deleteQuestion( q.getIdQuestion() );
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }
    }

    public static IUser createUser()
    {
        final String uName = "TESTusername";
        final String uPass = "^TEST^password^";

        UserDAO dao     = DAOFactory.getDAOFactory().getUserDAO();

        try {
            IUser user = dao.insertUser( uName, uPass );

            if( user!= null ) {

                user.setIdlocal( "fr" );
                user.setTimeZone( TimeZone.getDefault() );

                dao.updateUser( user );

                return user;
                }
            logger.warn( "can not create user (already exists?)" );
            return null;
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }
    }

    public static void deleteUser( final IUser user )
    {
        UserDAO dao = DAOFactory.getDAOFactory().getUserDAO();

        try {
            dao.deleteUser( user.getIdUser() );
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }
    }

    public static IReferent createReferent()
    {
        ReferentDAO dao = DAOFactory.getDAOFactory().getReferentDAO();

        final String referentPublicName         = "TEST Ref public Name";
        final String referentPublicDescription  = "TEST Ref public Description";
        final String referentUserName           = "TESTRefName";
        final String referentUserPassword       = "^TEST^RefPassword";

        try {
            return dao.insertReferent( referentPublicName, referentPublicDescription, referentUserName, referentUserPassword );
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }
    }

    public static void deleteReferent( final IReferent referent )
    {
        ReferentDAO dao = DAOFactory.getDAOFactory().getReferentDAO();

        try {
            dao.deleteReferent( referent.getIdReferent() );
            }
        catch( Exception e ) {
            logger.fatal( e );
            throw new RuntimeException( e );
            }
    }

}
